home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_11_01
/
1101057a
< prev
next >
Wrap
Text File
|
1992-11-07
|
6KB
|
240 lines
#include <iostream.h>
#include "tserial.h"
#include <string.h>
#include <dos.h>
#include <bios.h>
#include <conio.h>
// interrupt functions.
typedef void interrupt far intFunc(...);
// Programmed Interrupt Controller constants.
const PIC0 = 0x20;
const PIC1 = 0x21;
const EOI = 0x20;
// Offsets from port address.
const InterruptEnable = 1,
InterruptIdent = 2,
ModemControl = 4,
LineStatus = 5,
ModemStatus = 6;
// Value for the modem control register.
const ModemControlValue = 11;
// A serial port circular buffer class. There
// are only two instances of this class, one
// for each port COM1, and COM2. They are
// static globals, and are initailized before
// main(). They contain a circular buffer,
// the port number and port address, and the
// interrupt vector they replace, so that
// they can be restored at destruction. This
// is not a complete or robust class, and is
// private to this module. It is intended
// only for use by SerialStream.
class ComBuffer {
public:
// Size of circular buffer
enum { BufSize = 0x100 };
// Default constructor.
ComBuffer();
~ComBuffer();
// Set up vector, and enables interrupts
void hookInterrupt();
// Get a single character from the buffer
int getc();
// Send a single character to the port
void putc(int c);
// Read the line status register.
int status() const
{
return ::inp(portAddr+LineStatus);
}
// Check if characters are available
int avail() const
{
return in != out;
}
// Receive a character from port. This function
// is called by the interrupt routine.
void receive();
private:
// The mask needed for setting the PIC.
int interruptMask(int port) const
{
return 1 << (4 - port);
}
// The interrupt number for each port.
int interruptVec(int port) const
{
return 12 - port;
}
char *in, *out, *buff; // The circular buffer
int port; // The port number 0-1
int portAddr; // The port address
intFunc *oldVector; // The previos vector
static int initPort;
};
// initPort is used by the constructor to initialize
// the ports in sequence.
int ComBuffer::initPort = 0;
// Only two ports are set up here. If you add more
// you need to identify the port addresses and
// interrupt vectors.
static ComBuffer CommPorts[2];
// Initialize the buffers. Allocate the circular
// buffer, set the in/out pointers, set the port
// and port address values, and clear the old
// vector value.
ComBuffer::ComBuffer()
: buff(new char[BufSize]), port(initPort++),
oldVector(0)
{
// this line is for sceptics to see initializing.
cout << "initializing port #" << port << endl;
portAddr = port ? 0x2f8 : 0x3f8;
in = out = buff;
}
// Delete the circular buffer. If the old vector
// is a valid address, restore it.
ComBuffer::~ComBuffer()
{
// another line for sceptics.
cout << "de-initializing port #" << port << endl;
if(oldVector)
::setvect(interruptVec(port),oldVector);
delete[] buff;
}
// These two routines reset to PIC, and put
// the new character in the buffer
void interrupt far comInterrupt0(...)
{
::outp(PIC0,EOI);
CommPorts[0].receive();
}
void interrupt far comInterrupt1(...)
{
::outp(PIC0,EOI);
CommPorts[1].receive();
}
// This function sets up the interrupts, and
// enables the PIC
void
ComBuffer::hookInterrupt()
{
if(oldVector == 0)
oldVector = ::getvect(interruptVec(port));
switch(port)
{
case 0:
::setvect(interruptVec(port),comInterrupt0);
break;
case 1:
::setvect(interruptVec(port),comInterrupt1);
break;
default:
return;
}
::outp(portAddr+ModemControl,
::inp(portAddr+ModemControl)|ModemControlValue);
::outp(PIC1,::inp(PIC1) & ~interruptMask(port));
::outp(portAddr+InterruptEnable,1);
::outp(PIC0, EOI);
::inp(portAddr);
::inp(portAddr+InterruptIdent);
::inp(portAddr+ModemStatus);
status(); // clear status reg.
}
// Receive a byte from the port and place in the
// circular buffer, called from the interrupt
// handler.
void
ComBuffer::receive()
{
if(in == buff + BufSize)
in = buff; // circular buffer
*in++ = ::inp(portAddr);
}
// Get a character from the circular buffer.
int
ComBuffer::getc()
{
while(!avail())
if(::kbhit())
return -1;
if(out == buff + BufSize)
out = buff; // circular buffer
return *out++;
}
// Send a character directly to the port
void
ComBuffer::putc(int c)
{
while((status() & 0x20) == 0)
if(::kbhit())
return;
::outp(portAddr, c);
}
const default_init = _COM_1200|_COM_CHR8|
_COM_STOP1|_COM_NOPARITY;
// The open function needs to translate the name
// to the port number, initialize the port, and
// enable interrupts.
int SerialStream::open(const char *name, int, int)
{
if(::stricmp(name,"COM1") == 0)
port = 0;
else if(::stricmp(name, "COM2") == 0)
port = 1;
else
return -1;
unsigned int stat = ::_bios_serialcom(
_COM_INIT,port,default_init);
buffPtr = CommPorts+port;
buffPtr->hookInterrupt();
if(stat & 0xFF00)
return -1;
return 0;
}
// The close routine sets the port number to -1
// to indicate it's closed
int
SerialStream::close()
{
port = -1;
return 0;
}
// The read routine repeatedly calls ComBuffer::getc
// to fill it's buffer. len should always be 1.
int SerialStream::read(char *b, size_t len)
{
for(int i = 0; i < len; i++)
b[i] = buffPtr->getc();
return i;
}
// The write routine repeatedly calls ComBuffer::putc
// to empty it's buffer. len should alway be 1.
int SerialStream::write(char *b, size_t len)
{
for(int i = 0; i < len; i++)
buffPtr->putc(b[i]);
return i;
}